package org.xqh.utils.http;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.arronlong.httpclientutil.HttpClientUtil;
import com.arronlong.httpclientutil.common.HttpConfig;
import com.arronlong.httpclientutil.common.HttpMethods;
import com.arronlong.httpclientutil.common.HttpResult;
import com.arronlong.httpclientutil.exception.HttpProcessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;

/**
 * @ClassName FxHttpClientUtils
 * @Description TODO
 * @Date 2020/7/27 13:11
 * @Version 1.0
 */
@Slf4j
public class FxHttpClientUtils {

    private final static String DEFAULT_CHARSET = "UTF-8";

    /**
     * 获取httpConfig
     *
     * @param reqUrl
     * @return
     */
    public static HttpConfig getHttpConfig(String reqUrl) {
        return HttpConfig.custom()
                .url(reqUrl)
                .client(FxHttpPool.client)
                .encoding(DEFAULT_CHARSET)
                .timeout(6000)
                ;
    }

    /**
     *
     * @param reqUrl
     * @param headers
     * @param reqJson
     * @return
     */
    public static HttpConfig getPostJsonConfig(String reqUrl, Header[] headers, String reqJson){
        HttpConfig config = getHttpConfig(reqUrl);
        config.method(HttpMethods.POST);
        config.json(reqJson);
        config.headers(headers);
        return config;
    }

    public static HttpConfig getGetConfig(String reqUrl, Header[] headers){
        HttpConfig config = getHttpConfig(reqUrl);
        config.method(HttpMethods.GET);
        config.headers(headers);
        return config;
    }

    /**
     * 封装 解析 http请求结果
     *
     * @param httpRet
     * @param retData
     * @param retModel
     * @return
     */
    public static String wrapperReqResult(HttpResult httpRet, boolean retData, HttpRetModel retModel) throws IgHttpProcessException {
        if (httpRet.getStatusCode() == 200) {//http响应成功
            try {
                //拿到接口响应数据
                JSONObject retJson = JSON.parseObject(httpRet.getResult());
                if (Objects.nonNull(retJson)) {
                    if (retJson.getString(retModel.getStatusKey()).equals(retModel.getSuccessVal())) {
                        if (retData) {//需要返回 数据的 .
                            return retJson.getString(retModel.getDataKey());
                        }
                        return httpRet.getResult();//响应 接口 数据
                    } else {
                        // 接口响应数据 状态码 为 异常状态码
                        throw new IgHttpProcessException(httpRet.getResult());
                    }
                } else {
                    //接口数据解析异常
                    throw new IgHttpProcessException(httpRet.getResult());
                }
            } catch (Exception e) {
                // 解析json数据异常
                log.error("", e);
                //接口数据解析异常
                throw new IgHttpProcessException(httpRet.getResult());
            }
        } else {
            // http 请求
            throw new IgHttpProcessException(httpRet.getStatusCode(), httpRet.getResult());
        }
    }

    /**
     * http请求返回 string / 返回成功 or 失败 Or 接口失败描述
     *
     * @param config
     * @return
     */
    public static String requestReturnString(HttpConfig config) {
        return requestReturnString(config, new HttpRetModel());
    }


    public static String requestReturnString(HttpConfig config, HttpRetModel retModel) {
        try {
            HttpResult httpRet = HttpClientUtil.sendAndGetResp(config);
            return wrapperReqResult(httpRet, false, retModel);
        } catch (HttpProcessException e) {
            log.error("", e);
        }
        return "error";
    }

    /**
     * 请求返回 对象
     *
     * @param config
     * @param clz
     * @param <T>
     * @return
     */
    public static <T> T requestReturnObj(HttpConfig config, Class<T> clz) {
        return requestReturnObj(config, clz, new HttpRetModel());
    }

    public static <T> T requestReturnObj(HttpConfig config, Class<T> clz, HttpRetModel retModel) {
        try {
            HttpResult httpRet = HttpClientUtil.sendAndGetResp(config);
            String retStr = wrapperReqResult(httpRet, true, retModel);
            return JSON.parseObject(retStr, clz);
        } catch (HttpProcessException e) {
            log.error("", e);
        }
        return null;
    }

    /**
     * 返回 list
     *
     * @param config
     * @param clz
     * @param <T>
     * @return
     */
    public static <T> List<T> requestReturnList(HttpConfig config, Class<T> clz) {
        return requestReturnList(config, clz, new HttpRetModel());
    }

    /**
     * 自定义
     *
     * @param config
     * @param clz
     * @param retModel
     * @param <T>
     * @return
     */
    public static <T> List<T> requestReturnList(HttpConfig config, Class<T> clz, HttpRetModel retModel) {
        try {
            HttpResult httpRet = HttpClientUtil.sendAndGetResp(config);
            String retStr = wrapperReqResult(httpRet, true, retModel);
            if (StringUtils.hasText(retStr) && retStr.startsWith("[") && retStr.endsWith("]")) {
                return JSONArray.parseArray(retStr, clz);
            }
        } catch (HttpProcessException e) {
            log.error("", e);
        }
        return new ArrayList<>();
    }

    /**
     * POST 文件
     *
     * @param file
     * @param key
     * @param url
     * @param map
     * @return
     */
    public static String postFile(File file, String key, String url, Map<String, Object> map) {
        return postFiles(Arrays.asList(PostFile.builder()
                .file(file)
                .key(key)
                .build()), url, map);
    }

    public static String postFiles(List<PostFile> files, String url, Map<String, Object> map) {
        if (CollectionUtils.isEmpty(files)) {
            return null;
        }
        HttpConfig config = getHttpConfig(url)// 获取到 带连接池的 httpConfig
                .method(HttpMethods.POST) // 指定请求方式
                .map(map);
        files.stream().forEach(f -> {
            config.file(f.getFile(), f.getKey());
        });
        try {
            String requestRet = HttpClientUtil.upload(config);//上传
            return requestRet;
        } catch (HttpProcessException e1) {
            log.error("", e1);
        }
        return null;
    }

    /**
     * 文件下载
     * @param url
     * @param targetFile
     * @throws IOException
     */
    public static void downloadFile(String url, File targetFile, Header[] headers, String reqJson) throws IOException {
        /**
         * 文件下载
         */
        FileOutputStream outputStream = null;
        try {
            //指定 接收流对象
            outputStream = new FileOutputStream(targetFile);
            HttpConfig config = getHttpConfig(url)// 获取到 带连接池的 httpConfig
                    .method(HttpMethods.POST) // 指定请求方式
                    .headers(headers)
                    .json(reqJson)
                    .out(outputStream);
            HttpClientUtil.down(config);//下载文件
        } catch (Exception e) {
            log.error("", e);
        } finally {
            if (Objects.nonNull(outputStream)) {
                outputStream.close();
            }
        }
    }


    /**
     * 文件下载
     * @param url
     * @param targetFile
     * @throws IOException
     */
    public static void downloadFile(String url, File targetFile) throws IOException {
        /**
         * 文件下载
         */
        FileOutputStream outputStream = null;
        try {
            //指定 接收流对象
            outputStream = new FileOutputStream(targetFile);
            HttpConfig config = getHttpConfig(url)// 获取到 带连接池的 httpConfig
                    .method(HttpMethods.POST) // 指定请求方式
                    .out(outputStream);
            HttpClientUtil.down(config);//下载文件
        } catch (Exception e) {

        } finally {
            if (Objects.nonNull(outputStream)) {
                outputStream.close();
            }
        }
    }

}
